const { resolve } = require('path')
const { networkInterfaces } = require('os')
const merge = require('lodash/merge')
const Webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin-webpack5')

const root = process.cwd()
const cliRoot = resolve(__dirname, '..')

/**
 * 
 * @param { string } configPath 
 */
async function loadConfig(configPath = 'jm.config.js') {
  try{
    return require(resolve(root, configPath))
  }catch(e) {
    console.error(e)

    return {}
  }
}

const localIp = getLocalIp()

function getLocalIp() {
  var interfaces = networkInterfaces()
  for (var devName in interfaces) {
    var iface = interfaces[devName]
    for (var i = 0; i < iface.length; i++) {
      var alias = iface[i]
      if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
        return alias.address
      }
    }
  }
}

/**
 * 
 * @param { import('webpack-chain') } config
 */
function moduleRules(config) {

  config.module.rule('vue')
    .test(/\.vue$/)
    .use('vue-loader')
    .loader('vue-loader')
  config.plugin('vue-loader').use(VueLoaderPlugin)

  config.plugin('vueProvide').use(Webpack.ProvidePlugin, [{
    Vue: ['vue/dist/vue.esm.js', 'default']
  }])

  const jsRule = config.module
    .rule('js')
    .test(/\.(js|ts)x?$/)

  jsRule.exclude.add(/node_modules/)

  jsRule.use('babel-loader')
    .loader('babel-loader')

  const lessRule = config.module.rule('less')
    .test(/\.less$/)

  lessRule.use('style-loader').loader('style-loader')

  lessRule.use('css-loader').loader('css-loader')

  lessRule.use('less-loader')
    .loader('less-loader')
    .options({
      javascriptEnabled: true
    })


  const cssRule = config.module.rule('css')
    .test(/\.css$/)

  cssRule.use('style-loader').loader('style-loader')

  cssRule.use('css-loader').loader('css-loader')

  config.module.rule('xml')
    .test(/\.xml$/)
    .type('asset/source')

  config.module.rule('font')
    .test(/\.woff$|\.ttf$|\.woff2$|\.eot$/)
    .type('asset/inline')
  
  config.module.rule('picture')
    .test(/\.png$|\.svg$|\.gif$|\.jpg$|\.ico$/)
    .type('asset/inline')

  config.module.rule('file')
    .test(/\.wasm$|\.wsv$/)
    .type('asset')

    ;['.js', '.ts', '.jsx', '.vue', '.less', '.css', '.woff','.ttf','.wasm','.woff2','.wsv', '.png','.svg', '.gif', '.jpg', 'ico', 'eot'].forEach(key => {
      config.resolve.extensions.add(key)
    })

  return config
}

/**
 * 
 * @param { import("webpack-chain") } config 
 */
function resolveAlias(config) {
  ;[
    ['vue$', 'vue/dist/vue.esm.js'],
    ['packages', resolve(root, 'packages')],
    ['src', resolve(root, 'src')],
    ['cli', resolve(cliRoot, 'src')]
  ].forEach(([key, path]) => {
    config.resolve.alias.set(key, path)
  })

  return config
}

/**
 * 
 * @param { import("webpack-chain") } config 
 */
function resolveModules(config) {
  ;[
    'node_modules/jm-coms-cli/node_modules',
    'node_modules',
  ].forEach(modulePath => {
    config.resolve.modules.add(modulePath)
  })

  return config
}

function mapExternals(externals = []) {
  return externals.reduce((ret, key) => {
    if (typeof key === 'object') {
      Object.assign(ret, key)
    } else {
      ret[key] = key
    }

    return ret
  }, {})
}

/**
 * 
 * @param { import('webpack-chain') } config 
 */
function mergeJmConfig(config, jmConfig = {}) {

  jmConfig.webpackChain && jmConfig.webpackChain(config)

  if (jmConfig.webpackConfig) {
    return merge(config.toConfig(), jmConfig.webpackConfig)
  } else {
    return config.toConfig()
  }
}

/**
 * 
 * @param { import('webpack-chain') } config 
 */
function resolveLoaders(config) {

  config.resolveLoader.modules.add(resolve(cliRoot, 'node_modules'))
  config.resolveLoader.modules.add(resolve(root, 'node_modules'))

  return config
}

module.exports = {
  loadConfig,
  moduleRules,
  resolveModules,
  mapExternals,
  mergeJmConfig,
  getLocalIp,
  localIp,
  root,
  resolveLoaders,
  resolveAlias,
  cliRoot
}
